home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Programming / Complete Applications / Help«» / Docs / HT.c < prev   
Encoding:
C/C++ Source or Header  |  1985-08-23  |  31.7 KB  |  1,216 lines  |  [TEXT/ttxt]

  1. /*
  2.  * HelpText.c - source file for the "HELP«»TEXT" application
  3.  *
  4.  * Kent Kersten, 7-Jul-85
  5.  *
  6.  * This program takes a 'TEXT' type file and writes it to a given
  7.  * file's resource fork, under the resource name of 'HELP', with
  8.  * a given id # and (optional) name.  It can also perform the reverse
  9.  * operation, taking a HELP resource and writing a TEXT file.  This
  10.  * is helpful for preparing 'help' type dialogs, such as the type
  11.  * that Microsoft Multiplan has.
  12.  *
  13.  * NOTE:  The maximum size of a resource or text file is 32K bytes;
  14.  *        this is because we use TextEdit, and it has that limitation.
  15.  *        Also, you can't write a single resource that is greater
  16.  *        than 32K, so it works out all around.  Even so, I can't
  17.  *        imagine a single HELP selection being anywhere near that long!
  18.  *
  19.  * TEXT » HELP command instructions:
  20.  *     When you have a 'TEXT' type file, such as created with Edit,
  21.  *     and you wish to convert it to a HELP resource, this is the command
  22.  *     to use.  You will be presented with a Standard File dialog to
  23.  *     choose a TEXT type file to read from.  You will then be
  24.  *     prompted to enter a filename to save the HELP resource in.
  25.  *     The final dialog will ask you what resource number and name
  26.  *     you wish to assign to the resource.  If all goes well, you
  27.  *     will get a message to that effect; if not, then an appropriate
  28.  *     error message will be displayed.
  29.  *
  30.  * HELP » TEXT command instructions:
  31.  *     When you want to convert a HELP resource to a TEXT file, use
  32.  *     this command.  You will be prompted with a Standard File dialog
  33.  *     to choose a file to read the HELP resource from.  After that,
  34.  *     a dialog will open asking for the HELP resource number to use.
  35.  *     You will then be asked to name the TEXT file that the resource
  36.  *     will be written to.
  37.  *
  38.  * Please note that this program only works for vanilla text files.
  39.  * No formatting information is kept, such as with Microsoft Word.
  40.  *
  41.  * This program and its associated modules
  42.  * are the property of and copyright (c) 1985 by:
  43.  *     Kent Kersten
  44.  *     Harrison Systems
  45.  *     437 Atlas Drive
  46.  *     Nashville, TN  37211
  47.  *     (615) 834-1366
  48.  *     CompuServe [72277,2726]
  49.  */
  50.  
  51. #include  <quickdraw.h>
  52. #include  <window.h>
  53. #include  <menu.h>
  54. #include  <resource.h>
  55. #include  <packages.h>
  56. #include  <event.h>
  57. #include  <desk.h>
  58. #include  <control.h>
  59. #include  <textedit.h>
  60. #include  <dialog.h>
  61. #include  <font.h>
  62. #include  <osutil.h>
  63.  
  64. #define   copyright_string  "Copyright (c) 1985 by Kent Kersten"
  65.  
  66. #define   HELP_FILE        "\007HT.Help"
  67.  
  68. #define   ABOUT_DLOG        256
  69. #define   HELP_DLOG        257
  70. #define   RSRC_DLOG        300
  71. #define   RSRC_2_DLOG        301
  72. #define   OVERWRITE_DLOG    320
  73. #define   CONV_DLOG        350
  74. #define   GENERAL_ERROR_ALRT    400
  75.  
  76. #define   KENT_ICON        306
  77.  
  78. #define   nil            (long) 0
  79.  
  80. #define   NUM_MENUS        3
  81. #define   AppleMenu        256
  82. #define   FileMenu        257
  83. #define   EditMenu        258
  84.  
  85. #define   Helvetica        21        /* font for help boxes */
  86.  
  87. #define   MAX_TITLES_IN_BOX    7        /* how many can be seen at once */
  88. #define   MAX_HELP_TITLES    64
  89. #define   MAX_LINES_IN_BOX    14        /* # of lines in help text box */
  90.  
  91. MenuHandle HTMenu[NUM_MENUS];
  92.  
  93. char *calloc(), *realloc();
  94.  
  95. Boolean ProcessEvents(), DoCommand();
  96. Boolean ReadTextFile(), WriteTextFile();
  97. Boolean ReadRsrcFile(), WriteRsrcFile();
  98. Boolean OverWriteDialog(), RsrcDialog();
  99.  
  100. Point         whereOpen   = { 80, 80 };        /* where to put the SF dialog */
  101. Point         whereSaveAs = { 85, 95 };
  102.  
  103. struct hNode {
  104.      char *hName;            /* Pascal string */
  105.      int  hNum;
  106. } *hNodeList[MAX_HELP_TITLES];
  107.  
  108. Boolean noHelpResources, inHelpTextBox;
  109. int  selection, hTListNum;
  110. ControlHandle vsb;
  111. Rect htBox;
  112. TEHandle  hTE;
  113. pascal void DScrollUp(), DScrollDown();
  114.  
  115.  
  116. main()
  117. {
  118.      InitGraf(&thePort);
  119.      InitFonts();
  120.      InitWindows();
  121.      InitMenus();
  122.      InitDialogs(nil);
  123.      TEInit();
  124.  
  125.      FlushEvents(everyEvent, 0);        /* flush ALL events */
  126.      GetHelpTitles();
  127.      FormMenuBar();
  128.      InitCursor();
  129.  
  130.      Introduction();
  131.  
  132.      while(ProcessEvents())
  133.           ;
  134. }
  135.  
  136.  
  137. /*
  138.  * Create our menu bar.
  139.  */
  140.  
  141. FormMenuBar()
  142. {
  143.      int  i;
  144.  
  145.      HTMenu[0] = GetMenu(AppleMenu);
  146.      HTMenu[1] = GetMenu(FileMenu);
  147.      HTMenu[2] = GetMenu(EditMenu);
  148.      AddResMenu(HTMenu[0], 'DRVR');
  149.      
  150.      for(i = 0;i < NUM_MENUS;++i)
  151.           InsertMenu(HTMenu[i], 0);
  152.  
  153.      DrawMenuBar();
  154. }
  155.  
  156.  
  157. /*
  158.  * Get events and process them.
  159.  */
  160.  
  161. Boolean ProcessEvents()
  162. {
  163.      char         theChar;
  164.      Boolean      NoQuitFlag = TRUE;
  165.      WindowPtr    whichWindow;
  166.      EventRecord  EditEvent;
  167.      GrafPtr      savePort;
  168.  
  169.      HiliteMenu(0);            /* turn off any highlighting in menu bar */
  170.      SystemTask();
  171.  
  172.      GetNextEvent(everyEvent, &EditEvent);
  173.      switch(EditEvent.what) {
  174.           case mouseDown:
  175.                switch(FindWindow(pass(EditEvent.where), &whichWindow)) {    /* major Aztec C68K hack-ack */
  176.                     case inDesk:
  177.                          break;
  178.                     case inMenuBar:
  179.                          NoQuitFlag = DoCommand(MenuSelect(pass(EditEvent.where)));    /* Aztec hack */
  180.                          break;
  181.                     case inSysWindow:
  182.                          SystemClick(&EditEvent,whichWindow);
  183.                          break;
  184.                     case inGrow:
  185.                          break;
  186.                     case inContent:
  187.                          break;
  188.                     case inDrag:
  189.                          break;
  190.                     case inGoAway:
  191.                          break;
  192.                }
  193.                break;
  194.           case keyDown:
  195.           case autoKey:
  196.                theChar = EditEvent.message % 256;
  197.                if((EditEvent.modifiers & cmdKey) != 0)        /* command key pressed */
  198.                     NoQuitFlag = DoCommand(MenuKey(theChar));
  199.                break;
  200.           case updateEvt:
  201.                GetPort(&savePort);
  202.                SetPort(EditEvent.message);
  203.                BeginUpdate(EditEvent.message);
  204.                EndUpdate(EditEvent.message);
  205.                SetPort(savePort);
  206.                break;
  207.           case activateEvt:
  208.                break;
  209.      }
  210.  
  211.      return NoQuitFlag;
  212. }
  213.  
  214.  
  215. /*
  216.  * Decipher menu commands here.
  217.  */
  218.  
  219. Boolean DoCommand(command)
  220. long command;
  221. {
  222.      int     refNum;
  223.      char    name[256];
  224.      short   MenuNum, ItemNum;
  225.      Boolean NoQuitFlag = TRUE;
  226.  
  227.      InitCursor();
  228.      MenuNum = HiWord(command);
  229.      ItemNum = LoWord(command);
  230.  
  231.      switch(MenuNum) {
  232.           case AppleMenu:
  233.                if(ItemNum == 1) {
  234.             /* we have to bracket the call to our 'About' box with */
  235.             /* the open & close resource file calls, otherwise */
  236.             /* we could erroneously pick off a HELP resource from */
  237.             /* our .Help file when in 'HELPConvert()' */
  238.                     refNum = OpenResFile(HELP_FILE);
  239.                     AboutHT();
  240.                     CloseResFile(refNum);
  241.                }
  242.                else {
  243.                     GetItem(HTMenu[0], ItemNum, name);
  244.                     OpenDeskAcc(name);
  245.                }
  246.                break;
  247.           case FileMenu:
  248.                switch(ItemNum) {
  249.                     case 1:
  250.                          TEXTConvert();
  251.                          break;
  252.                     case 2:
  253.                          HELPConvert();
  254.                          break;
  255.                     case 3:
  256.                          NoQuitFlag = FALSE;
  257.                          break;
  258.                }
  259.                break;
  260.           case EditMenu:
  261.                switch(ItemNum) {
  262.                     case 1:
  263.                          if(FrontWindow() != nil)
  264.                               SystemEdit(undoCmd);
  265.                          break;
  266.                     case 3:
  267.                          if(FrontWindow() != nil)
  268.                               SystemEdit(cutCmd);
  269.                          break;
  270.                     case 4:
  271.                          if(FrontWindow() != nil)
  272.                               SystemEdit(copyCmd);
  273.                          break;
  274.                     case 5:
  275.                          if(FrontWindow() != nil)
  276.                               SystemEdit(pasteCmd);
  277.                          break;
  278.                     case 6:
  279.                          if(FrontWindow() != nil)
  280.                               SystemEdit(clearCmd);
  281.                          break;
  282.                }
  283.                break;
  284.      }
  285.  
  286.      return NoQuitFlag;
  287. }
  288.  
  289.  
  290. /*
  291.  * Get the string resource whose number was passed and
  292.  * call the GeneralError alert function.
  293.  */
  294.  
  295. ErrorCall(num)
  296. int  num;
  297. {
  298.      Handle hdl;
  299.  
  300.      hdl = GetString(num);
  301.      HLock(hdl);
  302.      GeneralError(*hdl, nil, nil, nil);
  303.      HUnlock(hdl);
  304.      ReleaseResource(hdl);
  305. }
  306.  
  307.  
  308. /*
  309.  * Convert a 'HELP' resource file to a 'TEXT' file.
  310.  */
  311.  
  312. HELPConvert()
  313. {
  314.      SFReply    rec, rec2;
  315.      int        id, number, refNum;
  316.      long       grow, theType;
  317.      char       name[256];
  318.      Handle     hdl;
  319.      Rect       tRect;
  320.      TEHandle   hTE;
  321.      WindowPtr  wptr;        /* a necessary hack, as it turns out */
  322.  
  323.      MaxMem(&grow);        /* free up some heap space */
  324.  
  325.      ParamText("\030Read HELP resource from:", nil, nil, nil);
  326.  
  327.      SFGetFile(pass(whereOpen), nil, nil, 0, nil, nil, &rec);
  328.  
  329.      if(rec.good == 0)                /* 'Cancel' button hit */
  330.           return;
  331.  
  332.      if(!RsrcDialog(&number, name, TRUE))
  333.           return;                /* 'Cancel' hit */
  334.  
  335.      if((refNum = OpenResFile(rec.fName)) < 0) { /* get the name of the resource */
  336.           ErrorCall(303);
  337.           return;
  338.      }
  339.  
  340.      if((hdl = GetResource('HELP', number)) == nil) {
  341.           CloseResFile(refNum);
  342.           ErrorCall(304);
  343.           return;
  344.      }
  345.      GetResInfo(hdl, &id, &theType, name);
  346.      ReleaseResource(hdl);
  347.      CloseResFile(refNum);
  348.  
  349.      hdl = GetString(257);
  350.      HLock(hdl);
  351.      SFPutFile(pass(whereSaveAs), *hdl, name, nil, &rec2);    /* text file to write to */
  352.      HUnlock(hdl);
  353.  
  354.      if(rec2.good == 0)                /* 'Cancel' hit */
  355.           return -1;
  356.  
  357.      SetRect(&tRect, 5000, 5000, 5050, 5050);    /* off the screen and invisible */
  358.      wptr = NewWindow(nil, &tRect, "\004Hack", FALSE, 0, (long) -1, FALSE, (long) 0);
  359.      tRect = wptr->portRect;
  360.      hTE = TENew(&tRect, &tRect);
  361.  
  362.      if(!ReadRsrcFile(rec.fName, number, hTE)) {
  363.           TEDispose(hTE);
  364.           DisposeWindow(wptr);
  365.           return;
  366.      }
  367.  
  368.      TECalText(hTE);        /* co-conspirators in the hack */
  369.      TEUpdate(&tRect, hTE);
  370.  
  371.      if(!WriteTextFile(rec2.fName, rec2.vRefNum, hTE)) {
  372.           TEDispose(hTE);
  373.           DisposeWindow(wptr);
  374.           return;
  375.      }
  376.  
  377.      TEDispose(hTE);
  378.      DisposeWindow(wptr);
  379.  
  380.      ConversionCompleted();
  381. }
  382.  
  383.  
  384. /*
  385.  * Convert a 'TEXT' file to a 'HELP' resource file.
  386.  */
  387.  
  388. TEXTConvert()
  389. {
  390.      SFReply    rec, rec2;
  391.      SFTypeList typeList;
  392.      short      numTypes = 1;
  393.      int        number;
  394.      long       grow;
  395.      char       temp[256], name[256];
  396.      Handle     hdl, hdl2;
  397.      Rect       tRect;
  398.      TEHandle   hTE;
  399.  
  400.      MaxMem(&grow);            /* clear out some heap space */
  401.  
  402.      typeList[0] = 'TEXT';
  403.  
  404.      ParamText("\017Read TEXT from:", nil, nil, nil);
  405.  
  406.      SFGetFile(pass(whereOpen), nil, nil, numTypes, typeList, nil, &rec);
  407.  
  408.      if(rec.good == 0)                /* 'Cancel' button hit */
  409.           return;
  410.  
  411.      Pstrcpy(temp, rec.fName);
  412.      ptoc(temp);
  413.      strcat(temp, ".Rsrc");        /* append ".Rsrc" to original filename */
  414.      ctop(temp);
  415.  
  416.      hdl = GetString(256);
  417.      HLock(hdl);
  418.      SFPutFile(pass(whereSaveAs), *hdl, temp, nil, &rec2);
  419.      HUnlock(hdl);
  420.  
  421.      if(rec2.good == 0)                /* 'Cancel' hit */
  422.           return -1;
  423.  
  424.      Pstrcpy(name, rec.fName);
  425.      if(!RsrcDialog(&number, name, FALSE))
  426.           return;            /* 'Cancel' hit */
  427.  
  428.      SetRect(&tRect, 2000, 2000, 2020, 2020);
  429.      hTE = TENew(&tRect, &tRect);
  430.  
  431.      if(!ReadTextFile(rec.fName, rec.vRefNum, hTE)) {
  432.           TEDispose(hTE);
  433.           return;
  434.      }
  435.  
  436.      if(!WriteRsrcFile(rec2.fName, name, number, hTE)) {
  437.           TEDispose(hTE);
  438.           return;
  439.      }
  440.  
  441.      TEDispose(hTE);
  442.  
  443.      ConversionCompleted();
  444. }
  445.  
  446.  
  447. /*
  448.  * Read from the resource file from the given filename & resource number,
  449.  * and put the info into the textedit handle passed.
  450.  */
  451.  
  452. Boolean ReadRsrcFile(fName, rNum, hTE)
  453. char *fName;
  454. int  rNum;
  455. TEHandle hTE;
  456. {
  457.      int  refNum;
  458.      Handle hdl;
  459.  
  460.      if((refNum = OpenResFile(fName)) < 0) {
  461.           ErrorCall(303);
  462.           return FALSE;
  463.      }
  464.  
  465.      if((hdl = GetResource('HELP', rNum)) == nil) {
  466.           CloseResFile(refNum);
  467.           ErrorCall(304);
  468.           return FALSE;
  469.      }
  470.  
  471.      TESetText(*hdl, SizeResource(hdl), hTE);
  472.  
  473.      ReleaseResource(hdl);
  474.      CloseResFile(refNum);
  475.  
  476.      return TRUE;
  477. }
  478.  
  479.  
  480. /*
  481.  * Read a TEXT file from the filename and refnum passed, and put the
  482.  * text into the textedit handle passed.
  483.  */
  484.  
  485. Boolean ReadTextFile(fname, vRefNum, hTE)
  486. char *fname;
  487. int  vRefNum;
  488. TEHandle hTE;
  489. {
  490.      int  refNum;
  491.      long logEOF;
  492.  
  493.      if(FSOpen(fname, vRefNum, &refNum) != 0) {
  494.           FSClose(refNum);
  495.           ErrorCall(300);
  496.           return FALSE;                /* file wasn't read */
  497.      }
  498.  
  499.      if(GetEOF(refNum, &logEOF) != 0) {
  500.           FSClose(refNum);
  501.           ErrorCall(312);
  502.           return FALSE;
  503.      }
  504.  
  505.      if(logEOF > 32000) {
  506.           FSClose(refNum);
  507.           ErrorCall(302);
  508.           return FALSE;
  509.      }
  510.  
  511.      SetHandleSize((*hTE)->hText, logEOF);
  512.  
  513.      if(FSRead(refNum, &logEOF, *((*hTE)->hText)) != 0) {
  514.           FSClose(refNum);
  515.           ErrorCall(313);
  516.           return FALSE;
  517.      }
  518.  
  519.      if(FSClose(refNum) != 0) {
  520.           ErrorCall(314);
  521.           return FALSE;
  522.      }
  523.  
  524.      (*hTE)->teLength = (int) logEOF;
  525.  
  526.      return TRUE;
  527. }
  528.  
  529.  
  530. /*
  531.  * Write to the resource file from the given filename, resource name & number,
  532.  * using the text referenced by the textedit handle.  Check to see if the
  533.  * resource already exists, and if so, allow them to cancel or continue.
  534.  */
  535.  
  536. Boolean WriteRsrcFile(fName, rName, rNum, hTE)
  537. char *fName, *rName;
  538. int  rNum;
  539. TEHandle hTE;
  540. {
  541.      int  refNum;
  542.      Handle hdl, hdl2;
  543.  
  544.      if((refNum = OpenResFile(fName)) < 0) {    /* doesn't exist, create it */
  545.           CreateResFile(fName);
  546.           if((refNum = OpenResFile(fName)) < 0) {    /* fatal error of some kind */
  547.                ErrorCall(305);
  548.                return FALSE;
  549.           }
  550.      }
  551.  
  552.      if((hdl = GetResource('HELP', rNum)) != nil)
  553.           if(!OverWriteDialog(fName, rName, rNum)) {
  554.                CloseResFile(refNum);
  555.                return FALSE;
  556.           }
  557.           else {
  558.                RmveResource(hdl);
  559.                if(ResError() < 0) {            /* remove failed */
  560.                     hdl2 = GetString(316);
  561.                     HLock(hdl2);
  562.                     GeneralError(*hdl2, nil, nil, nil);
  563.                     HUnlock(hdl2);
  564.                     CloseResFile(refNum);
  565.                     return FALSE;
  566.                }
  567.                DisposHandle(hdl);
  568.                UpdateResFile(refNum);
  569.           }
  570.  
  571.      AddResource((*hTE)->hText, 'HELP', rNum, rName);
  572.      UpdateResFile(refNum);
  573.      CloseResFile(refNum);
  574.  
  575.      return TRUE;
  576. }
  577.  
  578.  
  579. /*
  580.  * Write out the file, using the filename and refnum passed, and the
  581.  * text to write is referenced by the textedit handle.
  582.  */
  583.  
  584. Boolean WriteTextFile(fname, vRefNum, hTE)
  585. char *fname;
  586. int  vRefNum;
  587. TEHandle hTE;
  588. {
  589.      int  io_code, refNum;
  590.      long count;
  591.  
  592.      count = (long) (*hTE)->teLength;
  593.  
  594.      if((io_code = FSOpen(fname, vRefNum, &refNum)) != 0) {
  595.           if(io_code == -43) {            /* 'file not found' - create it! */
  596.                if(Create(fname, vRefNum, '    ', 'TEXT') != 0) {
  597.                     ErrorCall(315);
  598.                     return FALSE;
  599.                }
  600.                if(FSOpen(fname, vRefNum, &refNum) != 0) {
  601.                     ErrorCall(306);
  602.                     return FALSE;
  603.                }
  604.           }
  605.           else {
  606.                ErrorCall(307);
  607.                return FALSE;            /* error occurred during open */
  608.           }
  609.      }
  610.  
  611.      if(FSWrite(refNum, &count, *((*hTE)->hText)) != 0) {
  612.           ErrorCall(308);
  613.           return FALSE;
  614.      }
  615.  
  616.      if(SetEOF(refNum, count) != 0) {
  617.           ErrorCall(309);
  618.           return FALSE;
  619.      }
  620.  
  621.      if(FSClose(refNum) != 0) {
  622.           ErrorCall(310);
  623.           return FALSE;
  624.      }
  625.  
  626.      if(FlushVol(nil, vRefNum) != 0) {
  627.           ErrorCall(311);
  628.           return FALSE;
  629.      }
  630.  
  631.      return TRUE;
  632. }
  633.  
  634.  
  635. /********** dialog & alert routines begin here ***********/
  636.  
  637.  
  638. /*
  639.  * Pop up our 'About...' box.
  640.  */
  641.  
  642. AboutHT()
  643. {
  644.      int         i, type, itemHit = 0;
  645.      DialogPtr   DPtr;
  646.      Rect        tRect, i3Rect, i4Rect, i5Rect, i9Rect;
  647.      Handle      item, icon;
  648.      static long lastClickTime = 0;
  649.  
  650.      selection = 0;
  651.      inHelpTextBox = FALSE;
  652.  
  653.      icon = GetIcon(KENT_ICON);
  654.  
  655.      DPtr = GetNewDialog(ABOUT_DLOG, nil, (long) -1);    /* invisible */
  656.  
  657.      GetDItem(DPtr, 9, &type, &item, &i9Rect);        /* icon */
  658.      GetDItem(DPtr, 3, &type, &item, &i3Rect);        /* big box for help titles */
  659.      htBox = i3Rect;
  660.      GetDItem(DPtr, 4, &type, &item, &i4Rect);        /* scroll bar */
  661.      GetDItem(DPtr, 5, &type, &item, &i5Rect);        /* dashed line */
  662.  
  663.      ShowWindow(DPtr);
  664.      SetPort(DPtr);
  665.  
  666.      PlotIcon(&i9Rect, icon);
  667.  
  668.      PenPat(&gray);                /* dashed seperator line */
  669.      MoveTo(i5Rect.left, i5Rect.top);
  670.      LineTo(i5Rect.left, i5Rect.bottom);
  671.      PenNormal();
  672.  
  673.      FrameRect(&i3Rect);            /* big help titles box */
  674.  
  675.      vsb = NewControl(DPtr, &i4Rect, "\003vsb", (Boolean) -1, 0, 0, 0, scrollBarProc, (long) 0);
  676.  
  677.      GetDItem(DPtr, 2, &type, &item, &tRect);
  678.      if(noHelpResources)
  679.           HiliteControl((ControlHandle) item, 255);    /* disable 'Help' button */
  680.      else {                    /* put help titles into box */
  681.           if(hTListNum > MAX_TITLES_IN_BOX)
  682.                SetCtlMax(vsb, hTListNum - MAX_TITLES_IN_BOX);
  683.           HTDisplay();
  684.      }
  685.  
  686.      while(1) {
  687.           inHelpTextBox = FALSE;
  688.           ModalDialog(nil, &itemHit);
  689.           if(itemHit == 1) {                /* 'Cancel' */
  690.                CloseDialog(DPtr);
  691.                break;
  692.           }
  693.           else if(itemHit == 2) {            /* 'Help' */
  694.                CloseDialog(DPtr);
  695.                HelpDialog();
  696.                break;
  697.           }
  698.           else if(itemHit == 3) {            /* a title was selected */
  699.                if(noHelpResources)
  700.                     continue;
  701.                while(Button())            /* check for double-click */
  702.                     ;
  703.                if(TickCount() - lastClickTime <= GetDbleTime()) {
  704.                     CloseDialog(DPtr);
  705.                     HelpDialog();
  706.                     break;
  707.                }
  708.                else
  709.                     HTSelect();
  710.                lastClickTime = TickCount();
  711.           }
  712.           else if(itemHit == 4)                /* in scroll bar */
  713.                MyScroll((WindowPtr) DPtr);
  714.      }
  715. }
  716.  
  717.  
  718. /*
  719.  * This dialog tells the user that conversion process is over.
  720.  */
  721.  
  722. ConversionCompleted()
  723. {
  724.      int         itemHit = 0;
  725.      DialogPtr   DPtr;
  726.      EventRecord myRec;
  727.  
  728.      HiliteMenu(0);
  729.  
  730.      DPtr = GetNewDialog(CONV_DLOG, nil, (long) -1);
  731.      SetPort(DPtr);
  732.      DrawDialog(DPtr);
  733.  
  734.      while(!EventAvail(mDownMask | keyDownMask, &myRec))
  735.           ;            /* wait for a mouse down or key down event */
  736.  
  737.      CloseDialog(DPtr);
  738. }
  739.  
  740.  
  741. /*
  742.  * Pop up an alert box and pass some strings to tell what happened.
  743.  */
  744.  
  745. GeneralError(str1, str2, str3, str4)
  746. char *str1, *str2, *str3, *str4;            /* Pascal format */
  747. {
  748.      ParamText("\000", "\000", "\000", "\000");
  749.      ParamText(str1, str2, str3, str4);
  750.      StopAlert(GENERAL_ERROR_ALRT, nil);
  751. }
  752.  
  753.  
  754. /*
  755.  * Pop up the dialog box that actually displays the text of the help messages.
  756.  */
  757.  
  758. HelpDialog()
  759. {
  760.      int       itemHit, type;
  761.      Rect      box, textBox;
  762.      Handle    hdl;
  763.      DialogPtr DPtr;
  764.  
  765.      DPtr = GetNewDialog(HELP_DLOG, nil, (long) -1);
  766.      SetPort(DPtr);
  767.  
  768.      GetDItem(DPtr, 6, &type, &hdl, &textBox);
  769.      FrameRect(&textBox);
  770.      textBox.top += 1;                /* borders for help text */
  771.      textBox.left += 5;
  772.      textBox.bottom -= 1;
  773.      textBox.right -= 5;
  774.  
  775.      GetDItem(DPtr, 7, &type, &hdl, &box);
  776.      vsb = NewControl(DPtr, &box, "\003vsb", (Boolean) -1, 0, 0, 0, scrollBarProc, (long) 0);
  777.  
  778. loop:
  779.      inHelpTextBox = TRUE;
  780.  
  781.      GetDItem(DPtr, 3, &type, &hdl, &box);
  782.      if(selection == (hTListNum - 1))            /* disable 'Next' */
  783.           HiliteControl((ControlHandle) hdl, 255);
  784.      else
  785.           HiliteControl((ControlHandle) hdl, 0);
  786.  
  787.      GetDItem(DPtr, 4, &type, &hdl, &box);
  788.      if(selection == 0)                    /* disable 'Previous' */
  789.           HiliteControl((ControlHandle) hdl, 255);
  790.      else
  791.           HiliteControl((ControlHandle) hdl, 0);
  792.  
  793.      GetDItem(DPtr, 5, &type, &hdl, &box);        /* help title */
  794.      EraseRect(&box);
  795.      TextFont(systemFont);
  796.      MoveTo(box.left+2, box.bottom-3);
  797.      DrawString(hNodeList[selection]->hName);
  798.  
  799.      if((hdl = GetResource('HELP', hNodeList[selection]->hNum)) == nil) {
  800.           hdl = GetString(270);
  801.           HLock(hdl);
  802.           GeneralError(*hdl, nil, nil, nil);
  803.           HUnlock(hdl);
  804.           CloseDialog(DPtr);
  805.           return;
  806.      }
  807.  
  808.      hTE = TENew(&textBox, &textBox);
  809.      TESetText(*hdl, SizeResource(hdl) - 1, hTE);
  810.      ReleaseResource(hdl);        /* free the resource handle */
  811.  
  812.      (*hTE)->txFont = Helvetica;    /* Helvetica-12, in .Help file */
  813.      (*hTE)->crOnly = -1;        /* signals a wrap at newline only */
  814.      TECalText(hTE);
  815.      EraseRect(&textBox);        /* wipe out what was there before */
  816.      TEUpdate(&textBox, hTE);
  817.  
  818.      SetCtlValue(vsb, 0);
  819.  
  820.      if((*hTE)->nLines > MAX_LINES_IN_BOX)
  821.           SetCtlMax(vsb, (*hTE)->nLines - MAX_LINES_IN_BOX);
  822.      else
  823.           SetCtlMax(vsb, 0);
  824.  
  825.      while(1) {
  826.           ModalDialog(nil, &itemHit);
  827.           if(itemHit == 1) {                /* 'Cancel' */
  828.                CloseDialog(DPtr);
  829.                TEDispose(hTE);
  830.                break;
  831.           }
  832.           else if(itemHit == 2) {            /* 'Topics' */
  833.                CloseDialog(DPtr);
  834.                TEDispose(hTE);
  835.                AboutHT();
  836.                break;
  837.           }
  838.           else if(itemHit == 3) {            /* 'Next' */
  839.                TEDispose(hTE);
  840.                ++selection;
  841.                goto loop;
  842.           }
  843.           else if(itemHit == 4) {            /* 'Previous' */
  844.                TEDispose(hTE);
  845.                --selection;
  846.                goto loop;
  847.           }
  848.           else if(itemHit == 7)                /* scroll bar */
  849.                MyScroll();
  850.      }
  851. }
  852.  
  853.  
  854. /*
  855.  * A small graphical introduction to our program.
  856.  */
  857.  
  858. Introduction()
  859. {
  860.      Rect        boundsRect, theFrame;
  861.      DialogPtr   DPtr;
  862.      PicHandle   myPic;
  863.      EventRecord myRec;
  864.  
  865.      myPic = GetPicture(256);
  866.      theFrame = (*myPic)->picFrame;
  867.      OffsetRect(&theFrame, -theFrame.left + 5, -theFrame.top + 10);
  868.  
  869.      SetRect(&boundsRect, 120,60,390,250);
  870.  
  871.      DPtr = NewDialog(nil, &boundsRect, "\000", TRUE, 3, (long) -1, FALSE, (long) 0, nil);
  872.      SetPort(DPtr);
  873.  
  874.      HLock(myPic);
  875.      DrawPicture(myPic, &theFrame);
  876.      HUnlock(myPic);
  877.  
  878.      while(!EventAvail(mDownMask | keyDownMask, &myRec))    /* wait for a mouse or key event */
  879.           ;
  880.  
  881.      KillPicture(myPic);            /* free up the space */
  882.      CloseDialog(DPtr);
  883. }
  884.  
  885.  
  886. /*
  887.  * Pop up this dialog if a resource being written to already exists.
  888.  * The user has the option to cancel the operation or overwrite the
  889.  * existing resource in favor of the new one being created.
  890.  * Return TRUE to overwrite, FALSE otherwise.
  891.  */
  892.  
  893. Boolean OverWriteDialog(fileName, resName, resNumber)
  894. char *fileName, *resName;
  895. int  resNumber;
  896. {
  897.      int       itemHit = 0;
  898.      char      str[256];
  899.      DialogPtr DPtr;
  900.  
  901.      SysBeep(3);
  902.      sprintf(str, "%d", resNumber);
  903.      ParamText(fileName, ctop(str), resName, nil);
  904.  
  905.      DPtr = GetNewDialog(OVERWRITE_DLOG, nil, (long) -1);
  906.      SetPort(DPtr);
  907.  
  908.      while(1) {
  909.           ModalDialog(nil, &itemHit);
  910.           if(itemHit == 1) {                /* 'Overwrite' */
  911.                CloseDialog(DPtr);
  912.                return TRUE;
  913.           }
  914.           else if(itemHit == 2) {            /* 'Cancel' */
  915.                CloseDialog(DPtr);
  916.                return FALSE;
  917.           }
  918.      }
  919. }
  920.  
  921.  
  922. /*
  923.  * This dialog asks the user to input the resource name & number
  924.  * to use in the conversion process.  Return FALSE if the Cancel
  925.  * button was hit, else return TRUE.
  926.  */
  927.  
  928. Boolean RsrcDialog(number, name, use_help_dialog)
  929. int  *number;
  930. char *name;
  931. Boolean use_help_dialog;
  932. {
  933.      int       type, itemHit = 0;
  934.      char      str[256];
  935.      DialogPtr DPtr;
  936.      Handle    hdl;
  937.      Rect      box;
  938.  
  939.      if(use_help_dialog)
  940.           DPtr = GetNewDialog(RSRC_2_DLOG, nil, (long) -1);
  941.      else {
  942.           DPtr = GetNewDialog(RSRC_DLOG, nil, (long) -1);
  943.           GetDItem(DPtr, 6, &type, &hdl, &box);    /* resource number */
  944.           SetIText(hdl, name);        /* the text file's name as a default */
  945.      }
  946.  
  947.      SetPort(DPtr);
  948.  
  949.      while(1) {
  950.           ModalDialog(nil, &itemHit);
  951.           if(itemHit == 1) {                /* 'OK' */
  952.                GetDItem(DPtr, 4, &type, &hdl, &box);    /* resource number */
  953.                GetIText(hdl, &str);
  954.                *number = atoi(ptoc(str));
  955.                if(*number < 0 || *number > 32767) {
  956.                     hdl = GetString(317);
  957.                     HLock(hdl);
  958.                     GeneralError(*hdl, nil, nil, nil);
  959.                     HUnlock(hdl);
  960.                     continue;
  961.                }
  962.                GetDItem(DPtr, 6, &type, &hdl, &box);    /* resource name */
  963.                GetIText(hdl, &str);
  964.                Pstrcpy(name, str);
  965.                CloseDialog(DPtr);
  966.                return TRUE;
  967.           }
  968.           else if(itemHit == 2) {            /* 'Cancel' */
  969.                CloseDialog(DPtr);
  970.                return FALSE;
  971.           }
  972.      }
  973. }
  974.  
  975.  
  976. /********** support routines for the 'help' dialog stuff start here *********/
  977.  
  978.  
  979. /*
  980.  * Read the 'help' resource file and load all of the available
  981.  * names into the global list.  This is done at startup
  982.  * time, so that it will not have to be done every time that
  983.  * the 'About...' box is opened, thus saving some time.
  984.  */
  985.  
  986. GetHelpTitles()
  987. {
  988.      int    i, num, refNum;
  989.      long   rType;
  990.      char   name[256];
  991.      Rect   tRect;
  992.      Handle hdl;
  993.  
  994.      if((refNum = OpenResFile(HELP_FILE)) == -1)
  995.           noHelpResources = TRUE;
  996.      else {        /* check to make sure there are 'HELP' resources there */
  997.           if((hTListNum = CountResources('HELP')) == 0)    /* how many titles */
  998.                noHelpResources = TRUE;
  999.           else {
  1000.                noHelpResources = FALSE;
  1001.                for(i = 0;i < hTListNum;++i) {
  1002.                     hdl = GetIndResource('HELP', i+1);
  1003.                     GetResInfo(hdl, &num, &rType, name);
  1004.                     hNodeList[i] = (struct hNode *) calloc(1, sizeof(struct hNode));
  1005.                     hNodeList[i]->hName = calloc(1, (int) (name[0] + 1));
  1006.                     Pstrcpy(hNodeList[i]->hName, name);
  1007.                     hNodeList[i]->hNum = num;
  1008.                     ReleaseResource(hdl);
  1009.                }
  1010.           }
  1011.  
  1012.           CloseResFile(refNum);
  1013.      }
  1014. }
  1015.  
  1016.  
  1017. /*
  1018.  * Show the strings in a textbox sort of environment just like the
  1019.  * standard file package.  If one of the visible titles is selected,
  1020.  * then invert the rectangle around it, thus highlighting it.
  1021.  */
  1022.  
  1023. HTDisplay()
  1024. {
  1025.      int  i, ctl_value;
  1026.      Rect tRect;
  1027.  
  1028.      tRect = htBox;
  1029.  
  1030.      tRect.top += 1;
  1031.      tRect.left += 1;
  1032.      tRect.bottom = tRect.top + 16;
  1033.      tRect.right -= 1;
  1034.      ctl_value = GetCtlValue(vsb);
  1035.  
  1036.      for(i = ctl_value;i < hTListNum;++i) {
  1037.           if((i - ctl_value) == MAX_TITLES_IN_BOX)
  1038.                break;
  1039.           EraseRect(&tRect);
  1040.           MoveTo(tRect.left+2, tRect.bottom-4);
  1041.           DrawString(hNodeList[i]->hName);
  1042.  
  1043.           if(i == selection)
  1044.                InvertRect(&tRect);
  1045.           tRect.top += 16;
  1046.           tRect.bottom += 16;
  1047.      }
  1048. }
  1049.  
  1050.  
  1051. /*
  1052.  * Handle a mouse-down event in our 'box' that shows all of the
  1053.  * titles the user has to choose from.
  1054.  */
  1055.  
  1056. HTSelect()
  1057. {
  1058.      int  i, temp_i;
  1059.      Rect new_sel_rect, old_sel_rect, tRect;
  1060.      Point pt;
  1061.  
  1062.      SetRect(&old_sel_rect, 0, 0, 0, 0);        /* empty rect */
  1063.      new_sel_rect = old_sel_rect;
  1064.  
  1065.      tRect = htBox;
  1066.      tRect.top += 1;
  1067.      tRect.left += 1;
  1068.      tRect.bottom = tRect.top + 16;
  1069.      tRect.right -= 1;
  1070.      GetMouse(&pt);
  1071.  
  1072.      for(i = 0;i < MAX_TITLES_IN_BOX;++i) {
  1073.           if(PtInRect(pass(pt), &tRect)) {
  1074.                temp_i = i;
  1075.                new_sel_rect = tRect;
  1076.           }
  1077.  
  1078.           if(selection == (i + GetCtlValue(vsb)))
  1079.                old_sel_rect = tRect;
  1080.  
  1081.           tRect.top += 16;
  1082.           tRect.bottom += 16;
  1083.      }
  1084.  
  1085.      if(!EqualRect(&old_sel_rect, &new_sel_rect)) {    /* is the selection the same? */
  1086.           if(!EmptyRect(&old_sel_rect))            /* is it visible? */
  1087.                InvertRect(&old_sel_rect);
  1088.           if(temp_i < hTListNum) {
  1089.                selection = temp_i + GetCtlValue(vsb);
  1090.                InvertRect(&new_sel_rect);
  1091.           }
  1092.      }
  1093. }
  1094.  
  1095.  
  1096. /*
  1097.  * Handle the scroll bar we set up in our dialog.  This routine can
  1098.  * handle the titles box and the box where the help text appears, since
  1099.  * they are done differently.
  1100.  */
  1101.  
  1102. MyScroll(wptr)
  1103. WindowPtr wptr;
  1104. {
  1105.      int   max, oldValue;
  1106.      Point pt;
  1107.      ControlHandle whichControl;
  1108.  
  1109.      GetMouse(&pt);
  1110.      if(inHelpTextBox)
  1111.           max = MAX_LINES_IN_BOX;
  1112.      else
  1113.           max = MAX_TITLES_IN_BOX;
  1114.  
  1115.      switch(FindControl(pass(pt), wptr, &whichControl)) {
  1116.           case inUpButton:
  1117.                TrackControl(vsb, pass(pt), DScrollUp);
  1118.                break;
  1119.           case inDownButton:
  1120.                TrackControl(vsb, pass(pt), DScrollDown);
  1121.                break;
  1122.           case inPageUp:
  1123.                do {
  1124.                     GetMouse(&pt);
  1125.                     if(TestControl(whichControl, pass(pt)) == inPageUp) {
  1126.                          if(inHelpTextBox) {
  1127.                               oldValue = GetCtlValue(whichControl);
  1128.                               SetCtlValue(whichControl, oldValue - MAX_LINES_IN_BOX);
  1129.                               TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1130.                          }
  1131.                          else {
  1132.                               SetCtlValue(whichControl, GetCtlValue(whichControl) - MAX_TITLES_IN_BOX);
  1133.                               HTDisplay();
  1134.                          }
  1135.                     }
  1136.                } while(StillDown());
  1137.                break;
  1138.           case inPageDown:
  1139.                do {
  1140.                     GetMouse(&pt);
  1141.                     if(TestControl(whichControl, pass(pt)) == inPageDown) {
  1142.                          if(inHelpTextBox) {
  1143.                               oldValue = GetCtlValue(whichControl);
  1144.                               SetCtlValue(whichControl, oldValue + MAX_LINES_IN_BOX);
  1145.                               TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1146.                          }
  1147.                          else {
  1148.                               SetCtlValue(whichControl, GetCtlValue(whichControl) + MAX_TITLES_IN_BOX);
  1149.                               HTDisplay();
  1150.                          }
  1151.                     }
  1152.                } while(StillDown());
  1153.                break;
  1154.           case inThumb:
  1155.                oldValue = GetCtlValue(whichControl);
  1156.                TrackControl(whichControl, pass(pt), nil);
  1157.                if(inHelpTextBox)
  1158.                     TEScroll(0, (oldValue - GetCtlValue(whichControl)) * (*hTE)->lineHeight, hTE);
  1159.                else
  1160.                     HTDisplay();
  1161.                break;
  1162.      }
  1163.  
  1164. }
  1165.  
  1166.  
  1167. pascal void DScrollDown(theControl,theCode)
  1168. ControlHandle theControl;
  1169. int  theCode;
  1170. {
  1171.      if(theCode == inDownButton) {
  1172.           if(GetCtlValue(theControl) == GetCtlMax(theControl))
  1173.                return;                /* don't whip a dead horse */
  1174.           SetCtlValue(theControl, GetCtlValue(theControl) + 1);
  1175.           if(inHelpTextBox)
  1176.                TEScroll(0, -(*hTE)->lineHeight, hTE);
  1177.           else
  1178.                HTDisplay();
  1179.      }
  1180. }
  1181.  
  1182.  
  1183. pascal void DScrollUp(theControl,theCode)
  1184. ControlHandle theControl;
  1185. int  theCode;
  1186. {
  1187.      if(theCode == inUpButton) {
  1188.           if(GetCtlValue(theControl) == GetCtlMin(theControl))
  1189.                return;
  1190.           SetCtlValue(theControl, GetCtlValue(theControl) - 1);
  1191.           if(inHelpTextBox)
  1192.                TEScroll(0, (*hTE)->lineHeight, hTE);
  1193.           else
  1194.                HTDisplay();
  1195.      }
  1196. }
  1197.  
  1198.  
  1199. /************* miscellaneous routines that don't fit elsewhere *************/
  1200.  
  1201.  
  1202. /*
  1203.  * Copy a Pascal string to a pascal string.
  1204.  */
  1205.  
  1206. Pstrcpy(dest, src)
  1207. char *dest, *src;
  1208. {
  1209.      int  i;
  1210.  
  1211.      for(i = 1;i <= src[0];++i)
  1212.           dest[i] = src[i];
  1213.  
  1214.      dest[0] = src[0];
  1215. }
  1216.